home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Practical Algorithms for Image Analysis
/
Practical Algorithms for Image Analysis.iso
/
CH_4.1
/
CELLOG
/
CELLOG.C
< prev
next >
Wrap
C/C++ Source or Header
|
1999-09-11
|
10KB
|
312 lines
/*
* cellog.c
*
* Practical Algorithms for Image Analysis
*
* Copyright (c) 1997, 1998, 1999 MLMSoftwareGroup, LLC
*/
/* CELLOG: program performs cellular logic based on crossing number and
* factor number
* usage: cellog inimg outimg [-f FAC_THRESH] [-c CONNECTIVITY]
* [-i ITERATIONS] [-o OPERATION] [-I] [-L]
*/
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include "tiffimage.h" /* picfile info on images */
#include "images.h"
extern void print_sos_lic ();
#define ON 255 /* binarization values */
#define OFF 0
#define FAC_THRESH_DFLT 5 /* default threshold on factor number */
#define NITER_DFLT 1 /* default threshold on number iteratoins */
long crossnum (long *, long);
int usage (short);
int input (int, char **, long *, short *, long *, long *, long *);
main (argc, argv)
int argc;
char *argv[];
{
Image *imgI, *imgO; /* input and output image structures */
unsigned char **imgIn, **imgOut; /* input and output image arrays */
long width, height; /* size of image */
long facThresh; /* factor number threshold */
short connectFlag; /* =1 to retain connectivity; 0 otherwise */
long nIter; /* number of iterations to perform */
long opType; /* operation type */
long invertFlag; /* invert input image before processing */
long xEnd, yEnd; /* end of image within 1-pixel borders */
long ring[8]; /* neighborhood ring, top=ring[0] */
long fNum, cNum; /* factor number and crossing number */
long nChange; /* number pixels changed on iteration */
long x, y, i, n;
/* user input */
if ((input (argc, argv, &facThresh, &connectFlag, &nIter, &opType, &invertFlag)) < 0)
return (-1);
/* factor number has greater effect for larger number; number entered by
* user is for dilation, so for erosion, invert threshold value */
if (opType == 2 || opType == 4)
facThresh = 7 - facThresh;
/* open input and output image */
imgI = ImageIn (argv[1]);
imgIn = ImageGetPtr (imgI);
height = ImageGetHeight (imgI);
width = ImageGetWidth (imgI);
printf ("Input mage size is %dx%d.\n", width, height);
/* invert image */
if (invertFlag) {
for (y = 0; y < height; y++)
for (x = 0; x < width; x++)
imgIn[y][x] = 255 - imgIn[y][x];
}
imgO = ImageAlloc (height, width, 8);
imgOut = ImageGetPtr (imgO);
/* zero image borders */
yEnd = height - 1;
xEnd = width - 1;
for (y = 0; y < height; y++)
imgIn[y][0] = imgIn[y][xEnd] = OFF;
for (x = 0; x < width; x++)
imgIn[0][x] = imgIn[yEnd][x] = OFF;
/* write input to output image */
for (y = 0; y < height; y++)
for (x = 0; x < width; x++)
imgOut[y][x] = imgIn[y][x];
/* perform cellular logic iterations */
for (n = 0; n < nIter; n++) {
nChange = 0;
for (y = 1; y < yEnd; y++) {
for (x = 1; x < xEnd; x++) {
ring[0] = (imgIn[y - 1][x] > 0) ? 1 : 0;
ring[1] = (imgIn[y - 1][x + 1] > 0) ? 1 : 0;
ring[2] = (imgIn[y][x + 1] > 0) ? 1 : 0;
ring[3] = (imgIn[y + 1][x + 1] > 0) ? 1 : 0;
ring[4] = (imgIn[y + 1][x] > 0) ? 1 : 0;
ring[5] = (imgIn[y + 1][x - 1] > 0) ? 1 : 0;
ring[6] = (imgIn[y][x - 1] > 0) ? 1 : 0;
ring[7] = (imgIn[y - 1][x - 1] > 0) ? 1 : 0;
for (i = 0, fNum = 0; i < 8; i++)
fNum += ring[i];
cNum = crossnum (ring, 8);
if (connectFlag == 1 && cNum > 1);
else {
switch (opType) {
case 1: /* dilation */
if (fNum > facThresh) {
imgOut[y][x] = ON;
nChange++;
}
break;
case 2: /* erosion */
if (fNum < facThresh) {
imgOut[y][x] = OFF;
nChange++;
}
break;
case 3: /* dilation-erosion */
if (fNum > facThresh) {
imgOut[y][x] = ON;
nChange++;
}
break;
case 4: /* erosion-dilation */
if (fNum < facThresh) {
imgOut[y][x] = OFF;
nChange++;
}
break;
default:
usage (1);
}
}
}
}
printf ("iteration %d: nChange = %d\n", n, nChange);
for (y = 0; y < height; y++)
for (x = 0; x < width; x++)
imgIn[y][x] = imgOut[y][x];
if (opType == 4) {
opType = 3;
facThresh = 7 - facThresh;
}
else if (opType == 3) {
opType = 4;
facThresh = 7 - facThresh;
}
}
/* un-invert image */
if (invertFlag) {
for (y = 0; y < height; y++)
for (x = 0; x < width; x++)
imgOut[y][x] = 255 - imgOut[y][x];
}
ImageOut (argv[2], imgO);
return (0);
}
/* CROSSNUM: function calculates crossing number
* usage: crossnum (ring, nRing)
*/
long
crossnum (ring, nRing)
long *ring; /* ring of neighbors around center pixel */
long nRing; /* number of neighbors in ring */
{
long cNum; /* crossing number result */
long lower, upper; /* lower and upper members of ring */
long i, m, n, k;
k = 3;
/* calculate CNUM, first skipping corners */
for (i = 2, cNum = 0; i < nRing; i++) {
lower = (long) ring[i - 1];
if ((i % (k - 1)) == 0)
i++; /* skip the corner pixels */
upper = (long) ring[i];
if (upper != 0 && lower == 0)
cNum++;
}
if (ring[1] != 0 && ring[nRing - 1] == 0)
cNum++;
/* CNUM at corners */
for (n = 1; n < 4; n++) {
m = n * (k - 1);
if (ring[m] != 0) {
if (ring[m - 1] == 0 && ring[m + 1] == 0)
cNum++;
}
}
if (ring[0] != 0)
if (ring[1] == 0 && ring[nRing - 1] == 0)
cNum++;
return (cNum);
}
/* USAGE: function gives instructions on usage of program
* usage: usage (flag)
* When flag is 1, the long message is given, 0 gives short.
*/
int
usage (flag)
short flag; /* flag =1 for long message; =0 for short message */
{
/* print short usage message or long */
printf ("USAGE: cellog inimg outimg [-f FAC_THRESH] [-c CONNECTIVITY]\n");
printf (" [-i ITERATIONS] [-o OPERATION] [-I] [-L]\n");
if (flag == 0)
return (-1);
printf ("\ncellog performs cellular logic of input binary image.\n\n");
printf ("ARGUMENTS:\n");
printf (" inimg: input image filename (TIF)\n");
printf (" outimg: output image filename (TIF)\n\n");
printf ("OPTIONS:\n");
printf (" -f FAC_THRESH: factor number threshold, above which operation\n");
printf (" performed; (default = %d, range= 0-7)\n", FAC_THRESH_DFLT);
printf (" smaller the threshold value, the larger the effect\n");
printf (" -c: flag to maintain connectivity; default is not set.\n");
printf (" NOTE: this does not guarantee retention of,\n");
printf (" only maintains it better than not;\n");
printf (" if absolute retention is required,\n");
printf (" use KFILL or THIN program, depending on purpose.\n");
printf (" -i ITERATIONS: number of iterations to perform;\n");
printf (" (default = %d)\n", NITER_DFLT);
printf (" -o OPERATION: for dilation(1), erosion(2), closing(3),\n");
printf (" or opening(4) (default = 1).\n");
printf (" closing operation is alternating dilation-erosion;\n");
printf (" opening operation is alternating erosion-dilation;\n");
printf (" for opening or closing, the number of iterations is\n");
printf (" the sum of the comprising dilation and erosion iterations.\n");
printf (" -I: invert input image before processing\n");
printf (" -L: print Software License for this module\n");
return (-1);
}
/* INPUT: function reads input parameters
* usage: input (argc, argv, &facThresh, &connectFlag
* &nIter, &opType);
*/
#define USAGE_EXIT(VALUE) {usage (VALUE); return (-1);}
int
input (argc, argv, facThresh, connectFlag, nIter, opType, invertFlag)
int argc;
char *argv[];
long *facThresh; /* factor number threshold */
short *connectFlag; /* =1 to retain connectivity; 0 otherwise */
long *nIter; /* number of iterations to perform */
long *opType; /* operation type */
long *invertFlag; /* invert input image before processing */
{
long n;
if (argc == 1)
USAGE_EXIT (1);
if (argc == 2)
USAGE_EXIT (0);
*facThresh = FAC_THRESH_DFLT;
*connectFlag = 0;
*nIter = NITER_DFLT;
*opType = 1;
*invertFlag = 0;
for (n = 3; n < argc; n++) {
if (strcmp (argv[n], "-f") == 0) {
if (++n == argc || argv[n][0] == '-')
USAGE_EXIT (0);
*facThresh = atol (argv[n]);
}
else if (strcmp (argv[n], "-c") == 0)
*connectFlag = 1;
else if (strcmp (argv[n], "-i") == 0) {
if (++n == argc || argv[n][0] == '-')
USAGE_EXIT (0);
*nIter = atol (argv[n]);
}
else if (strcmp (argv[n], "-o") == 0) {
if (++n == argc || argv[n][0] == '-')
USAGE_EXIT (0);
*opType = atol (argv[n]);
}
else if (strcmp (argv[n], "-I") == 0)
*invertFlag = 1;
else if (strcmp (argv[n], "-L") == 0) {
print_sos_lic ();
exit (0);
}
else
USAGE_EXIT (0);
}
return (0);
}